package assignment04;

import gnu.trove.iterator.TIntIterator;
import gnu.trove.map.TIntIntMap;
import gnu.trove.map.hash.TIntIntHashMap;

import java.util.List;

import nlp.util.Indexer;

import assignment04.WordAlignmentTester.Alignment;
import assignment04.WordAlignmentTester.SentencePair;
import assignment04.WordAlignmentTester.WordAligner;

public class PMIWordAligner implements WordAligner {
	public static class Factory implements WordAlignerFactory {
		IntCounter frenchCounter;
		IntCounter englishCounter;
		IntCounterMap counterMap;
		Indexer<String> englishIndexer;
		Indexer<String> frenchIndexer;
		
		public WordAligner trainAligner(List<SentencePair> trainingSentencePairs) {
			buildIndexerAndCounter(trainingSentencePairs);
			normalizeCounter();
//			resolveScore();
			return new PMIWordAligner(frenchCounter, englishCounter, counterMap, englishIndexer, frenchIndexer);
		}
		
		private void buildIndexerAndCounter(List<SentencePair> trainingSentencePairs) {
			for (SentencePair pair : trainingSentencePairs) {
				List<String> eList = pair.englishWords;
				List<String> fList = pair.frenchWords;

				for (String eWord : eList) {
					englishCounter.incrementCount(englishIndexer.addAndGetIndex(eWord), 1.0);
				}
				
				for (String fWord : fList) {
					frenchCounter.incrementCount(frenchIndexer.addAndGetIndex(fWord), 1.0);
				}
				
				for (String french : fList) {
					int fIndex = frenchIndexer.indexOf(french);
					for (String english : eList) {
						int eIndex = englishIndexer.indexOf(english);
						counterMap.incrementCount(fIndex, eIndex, 1.0);
					}
				}
			}			
		}
		
		private void normalizeCounter() {
			frenchCounter.normalize();
			englishCounter.normalize();
			counterMap.normalize();
		}
		
		/**
		private void resolveScore() {
			for (TIntIterator ounterIt = counterMap.keySet().iterator(); ounterIt.hasNext();) {
				double maxScore = Double.NEGATIVE_INFINITY;
				int maxF = 0;
				int english = ounterIt.next();
				double pE = englishCounter.getCount(english);
				IntCounter counter = counterMap.getCounter(english);
				for (TIntIterator innerIt = counter.keySet().iterator(); innerIt.hasNext();) {
					int french = innerIt.next();
					double pF = frenchCounter.getCount(french);
					double pM = counter.getCount(french);
					double score = pM / pE / pF;
					if (score > maxScore) {
						maxScore = score;
						maxF = french;
					}
				}
			}
		}
		*/
		
		public Factory() {
			frenchCounter = new IntCounter();
			englishCounter = new IntCounter();
			counterMap = new IntCounterMap();
			
			englishIndexer = new Indexer<String>();
			frenchIndexer = new Indexer<String>();
		}
		
	}
	
	
	// TODO 
	public Alignment alignSentencePair(SentencePair sentencePair) {
	      return shit(sentencePair);
	}
	
	private Alignment shit(SentencePair sentencePair) {
		Alignment alignment = new Alignment();
		int numFrechWords = sentencePair.getFrenchWords().size();
	      int numEnglishWords = sentencePair.getEnglishWords().size();
	      for (int frenchPosition = 0; frenchPosition < numFrechWords; frenchPosition++) {
	    	  int maxPosition = -1;
	    	  double maxScore = Double.NEGATIVE_INFINITY;
	    	  String frenchWord = sentencePair.frenchWords.get(frenchPosition);
	    	  int frenchIndex = frenchIndexer.indexOf(frenchWord);
	    	  double pF = frenchCounter.getCount(frenchIndex);
	    	  for (int englishPosition = 0; englishPosition < numEnglishWords; englishPosition++) {
	    		  String englishWord = sentencePair.englishWords.get(englishPosition);
	    		  int englishIndex = englishIndexer.indexOf(englishWord);
	    		  double pE = englishCounter.getCount(englishIndex);
	    		  double pM = counterMap.getCount(frenchIndex, englishIndex);
	    		  double score = pM / pF / pE;
	    		  if (score > maxScore) {
	    			  maxScore = score;
	    			  maxPosition = englishPosition;
	    		  }
	    	  }
	    	  alignment.addAlignment(maxPosition, frenchPosition, true);
	      }
	      return alignment;
	}
	
	
	
	public PMIWordAligner(IntCounter frenchCounter, IntCounter englishCounter,
			IntCounterMap counterMap, Indexer<String> englishIndexer,
			Indexer<String> frenchIndexer) {
		this.frenchCounter = frenchCounter;
		this.englishCounter = englishCounter;
		this.counterMap = counterMap;
		this.englishIndexer = englishIndexer;
		this.frenchIndexer = frenchIndexer;

	}
	
	IntCounter frenchCounter;
	IntCounter englishCounter;
	IntCounterMap counterMap;
	Indexer<String> englishIndexer;
	Indexer<String> frenchIndexer;

}
